#pragma once
#include <stdio.h>
#include <stdlib.h>
#ifndef WSM2KEY
#define WSM2KEY

#define INVALID_NULL_VALUE_INPUT     0x1000
#define INVALID_INPUT_LENGTH         0x1001
#define CREATE_SM2_KEY_PAIR_FAIL     0x1002
#define COMPUTE_SM3_DIGEST_FAIL      0x1003
#define ALLOCATION_MEMORY_FAIL       0x1004
#define COMPUTE_SM2_SIGNATURE_FAIL   0x1005
#define INVALID_SM2_SIGNATURE        0x1006
#define VERIFY_SM2_SIGNATURE_FAIL    0x1007
#define EC_POINT_IS_AT_INFINITY      0x1008
#define COMPUTE_SM2_CIPHERTEXT_FAIL  0x1009
#define COMPUTE_SM2_KDF_FAIL         0x100a
#define INVALID_SM2_CIPHERTEXT       0x100b
#define SM2_DECRYPT_FAIL             0x100c

typedef struct sm2_key_pair_structure {
    /* Private key is a octet string of 32-byte length. */
    unsigned char pri_key[32];
    /* Public key is a octet string of 65 byte length. It is a
       concatenation of 04 || X || Y. X and Y both are SM2 public
       key coordinates of 32-byte length. */
    unsigned char pub_key[65];
} SM2_KEY_PAIR;
#endif
/**************************************************
* Name: w_sm2_create_key_pair
* Function: create SM2 key pair, including private key
    and public key
* Parameters:
    key_pair[in]  SM2 key pair
* Return value:
    0:                function executes successfully
    any other value:  an error occurs
**************************************************/
int w_sm2_create_key_pair(SM2_KEY_PAIR* key_pair);

/**************************************************
* Name: w_sm2_encrypt_data_test
* Function: compute SM2 encryption with a fixed internal
    random number k given in GM/T 0003.5-2012
* Parameters:
    message[in]      input message
    message_len[in]  input message length, size in bytes
    pub_key[in]      SM2 public key
    c1[out]          the first segment of ciphertext
    c3[out]          the middle segment of ciphertext
    c2[out]          the last segment of ciphertext
* Return value:
    0:                function executes successfully
    any other value:  an error occurs
* Notes:
1. This function is only used for testing! When a
   ciphertext is created by invoking this function,
   a fixed random number value k is used. The random
   number value is given in GM/T 0003.5-2012.
2. "pub_key" is a octet string of 65 byte length. It
   is a concatenation of 04 || X || Y. X and Y both are
   SM2 public key coordinates of 32 byte length.
3. SM2 ciphertext is defined as a concatenation of
   c1 || c3 || c2 in GM/T 0003.4-2012.
4. c1 is a octet string of 65 byte length. It is a
   point on the elliptic curve. It is a concatenation
   of 04 || X || Y. X and Y both are coordinates of
   32 byte length.
5. c3 is a octet string of 32 byte length. It is a
   SM3 digest value.
6. c2 is a octet string. Its length equals the length
   of input message.
**************************************************/
int w_sm2_encrypt_data_test(const unsigned char* message,
    const int message_len,
    const unsigned char* pub_key,
    unsigned char* c1,
    unsigned char* c3,
    unsigned char* c2);

/**************************************************
* Name: w_sm2_encrypt
* Function: compute SM2 encryption
* Parameters:
    message[in]      input message
    message_len[in]  input message length, size in bytes
    pub_key[in]      SM2 public key
    c1[out]          the first segment of ciphertext
    c3[out]          the middle segment of ciphertext
    c2[out]          the last segment of ciphertext
* Return value:
    0:                function executes successfully
    any other value:  an error occurs
* Notes:
1. pub_key is a octet string of 65 byte length. It
   is a concatenation of 04 || X || Y. X and Y both are
   SM2 public key coordinates of 32 byte length.
2. SM2 ciphertext is defined as a concatenation of
   c1 || c3 || c2 in GM/T 0003.4-2012.
3. c1 is a octet string of 65 byte length. It is a
   point on the elliptic curve. It is a concatenation
   of 04 || X || Y. X and Y both are coordinates of
   32 byte length.
4. c3 is a octet string of 32 byte length. It is a
   SM3 digest value.
5. c2 is a octet string. Its length equals the length
   of input message.
**************************************************/
int w_sm2_encrypt(const unsigned char* message,
    const int message_len,
    const unsigned char* pub_key,
    unsigned char* c1,
    unsigned char* c3,
    unsigned char* c2);

/**************************************************
* Name: w_sm2_decrypt
* Function: decrypt SM2 ciphertext
* Parameters:
    c1[in]            the first segment of ciphertext
    c3[in]            the middle segment of ciphertext
    c2[in]            the last segment of ciphertext
    c2_len[in]        c2 length, size in bytes
    pri_key[in]       SM2 private key
    plaintext[out]    decrypted result
* Return value:
    0:                function executes successfully
    any other value:  an error occurs
* Notes:
1. SM2 ciphertext is defined as a concatenation of
   c1 || c3 || c2 in GM/T 0003.4-2012.
2. c1 is a octet string of 65 byte length. It is a
   point on the elliptic curve. It is a concatenation
   of 04 || X || Y. X and Y both are coordinates of
   32 byte length.
3. c3 is a octet string of 32 byte length. It is a
   SM3 digest value.
4. c2 is a octet string. The length of plaintext is
   equal to c2_len.
5. pri_key is a octet string of 32 byte length.
**************************************************/
int w_sm2_decrypt(const unsigned char* c1,
    const unsigned char* c3,
    const unsigned char* c2,
    const int c2_len,
    const unsigned char* pri_key,
    unsigned char* plaintext);

/**************************************************
* Name: w_test_with_input_defined_in_standard
* Function: test SM2 encrypt data and decrypt ciphertext
    with standard input from GM/T 0003.5-2012
* Return value:
    0:                test executes successfully
    any other value:  an error occurs
**************************************************/
int w_test_with_input_defined_in_standard(void);

/**************************************************
* Name: w_test_sm2_encrypt_and_decrypt
* Function: test SM2 encrypt data and decrypt ciphertext
* Return value:
    0:                test executes successfully
    any other value:  an error occurs
**************************************************/
int w_test_sm2_encrypt_and_decrypt(void);